package core.matrix;

import core.iterfaces.Matrix;
import core.iterfaces.Vec;
import core.vec.SparseVec;
import exception.NotSupportException;

import java.util.HashMap;
import java.util.Map;

/**
 * 稀疏矩阵
 */
public class SparseMatrix implements Matrix {
    /**
     * 数据
     */
    private Map<Integer,Double> data;

    private Integer colLen;

    private Integer rowLen;

    public SparseMatrix(){
        this.colLen = 0;
        this.rowLen = 0;
        data = new HashMap<>(0);
    }


    public SparseMatrix(Integer rowLen,Integer colLen){
        this.colLen = colLen;
        this.rowLen = rowLen;
        data = new HashMap<>(0);
    }

    public Matrix copy(){
        SparseMatrix result = new SparseMatrix(this.rowLen,this.colLen);
        for (int i = 0; i < rowLen; i++) {
            for (int j = 0; j < colLen; j++) {
                result.set(i,j, result.get(i,j));
            }
        }
        return result;
    }

    @Override
    public Matrix zero() {
        return new SparseMatrix();
    }

    @Override
    public Matrix zero(int rowLen, int colLen) {
        return new SparseMatrix(rowLen,colLen);
    }

    @Override
    public double get(int i, int j) {
        if(i<0||i>rowLen-1){
            throw new IndexOutOfBoundsException("传入的参数i:"+i+" 不符合矩阵行数范围");
        }
        if(j<0||j>colLen-1){
            throw new IndexOutOfBoundsException("传入的参数j:"+j+" 不符合矩阵列数范围");
        }
        if(data.containsKey(i*colLen+j)){
            return data.get(i*colLen+j);
        }
        return 0;
    }

    @Override
    public void set(int i, int j, double value) {
        if(i<0||i>rowLen-1){
            throw new IndexOutOfBoundsException("传入的参数i:"+i+" 不符合矩阵行数范围");
        }
        if(j<0||j>colLen-1){
            throw new IndexOutOfBoundsException("传入的参数j:"+j+" 不符合矩阵列数范围");
        }
        if(value!=0) {
            data.put(i * colLen + j, value);
        }
    }

    @Override
    public Vec getRow(int i) throws NotSupportException {
        if(i<0||i>rowLen-1){
            throw new IndexOutOfBoundsException("传入的参数i:"+i+" 不符合矩阵行数范围");
        }
        SparseVec result = new SparseVec(colLen);
        for(int j=0;j<colLen;j++){
            if(data.containsKey(i*colLen+j)){
                result.set(j,get(i,j));
            }
        }
        return result;
    }

    @Override
    public Vec getCol(int j) {
        if(j<0||j>colLen-1){
            throw new IndexOutOfBoundsException("传入的参数j:"+j+" 不符合矩阵列数范围");
        }
        SparseVec result = new SparseVec(rowLen);
        for(int i=0;i<rowLen;i++){
            if(data.containsKey(i*rowLen+j)){
                result.set(i,get(i,j));
            }
        }
        return result;
    }

    @Override
    public Vec getSubRow(int i, int begin, int end) throws NotSupportException {
        if(i<0||i>rowLen-1){
            throw new IndexOutOfBoundsException("传入的参数i:"+i+" 不符合矩阵行数范围");
        }
        if(begin<0||begin>colLen-1){
            throw new IndexOutOfBoundsException("传入的参数begin:"+begin+" 不符合矩阵列数范围");
        }
        if(end<0||end>colLen){
            throw new IndexOutOfBoundsException("传入的参数end:"+end+" 不符合矩阵列数范围");
        }
        SparseVec result = new SparseVec(end-begin);
        for (int j = begin; j < end; j++) {
            result.set(j,get(i,j));
        }
        return result;
    }

    @Override
    public Vec getSubCol(int j, int begin, int end) throws NotSupportException {
        if(j<0||j>colLen-1){
            throw new IndexOutOfBoundsException("传入的参数j:"+j+" 不符合矩阵列数范围");
        }
        if(begin<0||begin>rowLen-1){
            throw new IndexOutOfBoundsException("传入的参数begin:"+begin+" 不符合矩阵行数范围");
        }
        if(end<0||begin>rowLen){
            throw new IndexOutOfBoundsException("传入的参数end:"+end+" 不符合矩阵行数范围");
        }
        SparseVec result = new SparseVec(end-begin);
        for (int i = begin;  i< end; i++) {
            result.set(i,get(i,j));
        }
        return result;
    }

    @Override
    public int getRowLen() {
        return rowLen;
    }

    @Override
    public int getColLen() {
        return colLen;
    }

    @Override
    public boolean isDense() {
        return false;
    }

    @Override
    public boolean isPositiveDefinite() {
        return false;
    }

    @Override
    public double norm2() {
        return 0;
    }

    @Override
    public Matrix toSparse() throws NotSupportException {
        return copy();
    }

    @Override
    public Matrix toDense() throws NotSupportException {
        DenseMatrix result = new DenseMatrix(this.rowLen,this.colLen);
        for (int i = 0; i < rowLen; i++) {
            for (int j = 0; j < colLen; j++) {
                result.set(i,j, get(i,j));
            }
        }
        return result;
    }
}
